
package com.fl.util;

import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 获取配置文件工具类
 * 
 */
public class PropertyUtil {

	private static PropertyUtil instance = null;

	/**
	 * modify by xhlin 20111228 去掉分隔符
	 */
	private static final String FILE_FOLDER = "appCfg";

	private static Map<String, Properties> mapConfigProperties = new ConcurrentHashMap<String, Properties>();

	private PropertyUtil() {

	}

	/**
	 * singleton模式
	 */
	public synchronized static PropertyUtil getInstance() {
		if (instance == null) {
			instance = new PropertyUtil();
		}
		return instance;
	}

	/**
	 * 根据指定目录下的文件名称获取属性文件的内容
	 * 
	 * @param dir
	 *            相对路径
	 * @param fileName
	 * @return Properties对象
	 */
	public Properties getPropertiesByFileName(String dir, String fileName)
			throws IOException {
		// 根据文件名构造URL对象
		String _fileName;
		if (dir != null && dir.trim().length() > 0) {
			_fileName = dir + File.separator + fileName;
		} else {
			_fileName = fileName;
		}

		Properties prop = mapConfigProperties.get(_fileName);
		if (prop != null) {
			return prop;
		} else {
			// add xhlin 从新的方法获取资源
			URL url = getConfigResourceUrl(_fileName);
			// url = getConfigURL(_fileName);
			if (url == null) {
				throw new IOException("Can not find property file,file="
						+ _fileName);
			}
			// 创建属性对象并从获得的URL中读出属性。
			Properties p = new Properties();
			try {
				System.out.println(_fileName
						+ " properties file found and used:URL="
						+ url.toExternalForm());
				p.load(url.openStream());
			} catch (IOException ioe) {
				throw new IOException("Can not load property file,file URL="
						+ url.toExternalForm(), ioe);
			}
			mapConfigProperties.put(_fileName, p);
			return p;
		}

	}

	/**
	 * 根据指定目录下的文件名称获取属性文件的内容,不用写路径，默认从appCfg/找
	 * 
	 * @param fileName
	 * @return Properties对象
	 */
	public Properties getPropertiesByFileName(String fileName)
			throws IOException {
		return getPropertiesByFileName(null, fileName);
	}

	/**
	 * 根据指定目录下的文件名称获取属性文件的内容中对应Key的具体value值
	 * 
	 * @param dir
	 *            相对路径
	 * @param fileName
	 * @param key
	 * @return value值
	 */
	public String getValueByFileNameKey(String dir, String fileName, String key)
			throws IOException {
		return (String) getPropertiesByFileName(dir, fileName).get(key);
	}

	/**
	 * 取默认appCfg下文件的对应Key的具体value值
	 * 
	 * @param fileName
	 * @param key
	 * @return value值
	 */
	public String getValueByDefaultFileKey(String fileName, String key)
			throws IOException {
		return (String) getPropertiesByFileName(null, fileName).get(key);
	}

	/**
	 * 查找资源步骤<br>
	 * 1、先在当前的classloader的根下查找资源，不带appCfg，如果war的classes下放了资源则在这里返回；如果为绝对路径则也在这里定位资源后返回<br>
	 * 2、上面定位不到资源再在appCfg下查找资源，先在当前的classLoader的appCfg下查找，找不到再在bootstrapClassPath的appCfg下查找,
	 * 这里定位到资源的情况为，在war的classes下放了appCfg目录，或者在cup-deploy下放了appCfg目录，并把资源放入此目录下<br>
	 * 3、上面定位不到资源再按照2的步骤重复查找，区别为不在appCfg下查找资源，而是在根下直接查找，这里可能出现的情况为，应用忘记配置文件，
	 * 比如log4j的配置文件，那么最终会定位到bootstrapClasspath的中间件的配置文件(jboss里表现为run.jar里的log4j.properties)
	 * @param resource
	 * @return
	 */
	public URL getConfigResourceUrl(String resource) {
		URL url = null;
		// 相对路径查找当前classloader的资源；绝对路径查找绝对路径的资源，另外提供绝对路径的访问方法，不要在此处混用，造成太多的错误
		try {
			File configFile = new File(resource);
			url = configFile.toURI().toURL();
			url.openStream();
		} catch (MalformedURLException mue) {
			url = null;
		} catch (IOException e) {
			url = null;
		}
		
		// 先查找appCfg下的资源
		// 查找路径可参考方法ClassLoader.getResource(),先查找当前classloader的资源，如果查找不到再找bootstrapclassPath下的资源
		// 注意流传到此处后，如果配置文件可能与中间件的混淆而应用又没有配置的情况，则可能发生直接使用中间件的配置文件情况。
		if (url == null) {
			url = Thread.currentThread().getContextClassLoader()
					.getResource(FILE_FOLDER+File.separatorChar+resource);
		}

		// 再查找classPath下的资源
		// 查找路径可参考方法ClassLoader.getResource(),先查找当前classloader的资源，如果查找不到再找bootstrapclassPath下的资源
		// 注意流传到此处后，如果配置文件可能与中间件的混淆而应用又没有配置的情况，则可能发生直接使用中间件的配置文件情况。
		if (url == null) {
			url = Thread.currentThread().getContextClassLoader()
					.getResource(resource);
		}

		return url;
	}

}
